package org.example.pingpong.service.Impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.xiaoymin.knife4j.core.util.StrUtil;
import org.example.pingpong.common.exception.ForbiddenException;
import org.example.pingpong.domain.dto.UserFormDTO;
import org.example.pingpong.domain.po.User;
import org.example.pingpong.domain.vo.Result;
import org.example.pingpong.mapper.UserMapper;
import org.example.pingpong.service.EmailService;
import org.example.pingpong.service.RedisService;
import org.example.pingpong.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author 郑凯
 * @description 针对表【user】的数据库操作Service实现
 * @createDate 2025-02-12 18:53:05
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper; // 注入UserMapper，用于执行数据库操作
    @Resource
    private RedisService redisService;
    @Resource
    private EmailService emailService;

    /**
     * 创建用户
     * 该方法首先检查用户名和邮箱是否已存在，然后将用户信息保存到数据库。
     * 如果操作成功，返回成功的响应；如果失败，返回具体的失败原因。
     *
     * @param userFormDTO 用户提交的表单数据
     * @return Result<Void> 返回操作结果，成功时无数据，失败时包含错误信息
     */
    @Override
    public UserFormDTO createUser(UserFormDTO userFormDTO) {
        // 检查用户名是否已存在
        boolean exist = this.checkUserExistByUsername(userFormDTO.getUsername());
        if (exist) {
            throw new ForbiddenException("用户名已存在"); // 如果用户名已存在，返回失败信息
        }

        // 如果邮箱为空，则检查邮箱是否已存在
        if (StrUtil.isNotBlank(userFormDTO.getEmail())) {
            exist = this.checkUserExistByEmail(userFormDTO.getEmail());
            if (exist) {
                throw new ForbiddenException("邮箱已存在"); // 如果邮箱已存在，返回失败信息
            }
        } else {
            // 如果邮箱不为空，设置邮箱
            userFormDTO.setEmail(userFormDTO.getEmail());
        }

        // 创建用户并复制字段到PO对象中
        User user = new User();
        // 创建用户名和密码身份信息并保存
        user = this.createUsernamePasswordIdentity(user.getId(), userFormDTO.getUsername(), userFormDTO.getPassword(), userFormDTO.getNickname(), userFormDTO.getEmail());

        // 插入用户到数据库
        this.baseMapper.insert(user);

        // 返回成功结果
        UserFormDTO resultDTO = new UserFormDTO();
        BeanUtils.copyProperties(user, resultDTO);  // 将PO的属性复制到DTO对象中
        return resultDTO; // 返回包含用户信息的DTO
    }

    /**
     * 检测数据合法性
     *
     * @param validator
     * @return CreatedVO
     */
    @Override
    public Result userDataCheck(UserFormDTO validator) {
        // 先判断元素是否有空
        if (validator.getUsername().isEmpty() || validator.getNickname().isEmpty()
                || validator.getEmail().isEmpty() || validator.getPassword().isEmpty()) {
            return Result.fail(410, "填写的账号内容缺失,请检查");
        }
        if (!validator.getUsername().matches("^\\S{5,16}$")) {
            return Result.fail(412, "用户名格式错误");
        }
        if (!validator.getPassword().matches("^\\S{5,16}$")) {
            return Result.fail(413, "密码格式错误");
        }
        if (validator.getCode().isEmpty()) {
            return Result.fail(411, "请获取验证码");
        }
        Result result = this.EmailDataCheck(validator.getEmail(), redisService.getMailCode(validator.getEmail()));
        if (result.getStatus() != 200) {
            return Result.fail(result.getStatus(), result.getMsg());
        }
        // 使用 QueryWrapper 判断是否有重复的用户名、邮箱或昵称
        QueryWrapper<User> wrapper = new QueryWrapper<>();

        // 确保字段非空并且使用正确的 getter 方法
        if (StrUtil.isNotBlank(validator.getUsername())) {
            wrapper.eq("username", validator.getUsername().trim()); // 去掉多余的空格
        }
        if (StrUtil.isNotBlank(validator.getEmail())) {
            wrapper.eq("email", validator.getEmail().trim()); // 去掉多余的空格
        }
        if (StrUtil.isNotBlank(validator.getNickname())) {
            wrapper.eq("nickname", validator.getNickname().trim()); // 去掉多余的空格
        }

        List<User> users = userMapper.selectList(wrapper);  // 使用正确的实体类进行查询

        // 遍历查找是否存在重复的用户名、邮箱或昵称
        for (User u : users) {
            if (u.getUsername() != null && u.getUsername().equalsIgnoreCase(validator.getUsername())) {
                return Result.fail(415, "用户已存在,请更换其他账号进行注册");
            }
            if (u.getEmail() != null && u.getEmail().equals(validator.getEmail())) {
                return Result.fail(416, "邮箱已被使用，请重新填入新的邮箱");
            }
            if (u.getNickname() != null && u.getNickname().equalsIgnoreCase(validator.getNickname())) {
                return Result.fail(417, "昵称已被使用,请重新填入新的昵称");
            }
        }

        // 如果一切检查通过, 删除验证码缓存并允许注册
        redisService.delMailCode(validator.getEmail());

        return Result.success(200);
    }

    /**
     * @param email 用户邮箱
     * @param code  验证码
     * @return 检查结果
     */
    @Override
    public Result EmailDataCheck(String email, String code) {
        // 验证邮箱格式
        if (!isValidEmail(email)) {
            return Result.fail(412, "邮箱格式无效，请检查邮箱地址");
        }
        // 检查验证码是否存在并且有效
        String cachedCode = redisService.getMailCode(email);
        if (cachedCode == null) {
            return Result.fail(413, "验证码无效或已过期");
        }
        // 判断验证码是否正确
        if (!cachedCode.equals(String.valueOf(code))) {
            return Result.fail(414, "验证码错误");
        }
        return Result.success(200);
    }

    /**
     * 校验邮箱格式是否有效
     *
     * @param email 邮箱地址
     * @return 是否有效
     */
    private boolean isValidEmail(String email) {
        String emailRegex = "^[A-Za-z0-9+_.-]+@([A-Za-z0-9.-]+\\.)+[A-Za-z]{2,}$";
        Pattern pattern = Pattern.compile(emailRegex);
        Matcher matcher = pattern.matcher(email);
        return matcher.matches();
    }

    /**
     * 创建用户名和密码身份信息
     * 该方法会对密码进行加密，并将用户名与加密后的密码存储到数据库中。
     *
     * @param userId     用户ID
     * @param identifier 用户名
     * @param credential 密码
     */
    @Override
    public User createUsernamePasswordIdentity(Integer userId, String identifier, String credential, String nickName, String email) {
        // 对密码进行加密
        String encryptedPassword = encryptPassword(credential); // 加密密码

        // 创建新的用户实体并设置其值
        User user = new User();
        user.setId(userId);
        user.setUsername(identifier);
        user.setEmail(email);
        user.setNickname(nickName);
        user.setPassword(encryptedPassword);

        return user; // 返回包含用户信息的DTO
    }


    /**
     * 密码加密方法
     * 这里简单示范如何加密密码，实际使用中应根据项目安全要求选择合适的加密算法（如BCrypt）。
     *
     * @param password 原始密码
     * @return String 加密后的密码
     */
    public String encryptPassword(String password) {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder.encode(password);  // 使用BCrypt加密密码
    }

    public boolean checkUserPassword(String password, String encryptedPassword) {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder.matches(password, encryptedPassword);
    }


    /**
     * 检查用户名是否存在
     *
     * @param username 用户名
     * @return boolean 如果用户名已存在，返回true，否则返回false
     */
    public boolean checkUserExistByUsername(String username) {
        return userMapper.existsByUsername(username);
    }

    /**
     * 检查邮箱是否已存在
     *
     * @param email 用户邮箱
     * @return boolean 如果邮箱已存在，返回true，否则返回false
     */
    public boolean checkUserExistByEmail(String email) {
        return userMapper.existsByEmail(email);
    }

    /**
     * 删除指定条件的用户
     *
     * @param wrapper 查询条件
     * @return 删除的记录数
     */
    public int del(Wrapper wrapper) {
        return userMapper.delete(wrapper);
    }

    /**
     * 查询符合条件的用户列表
     *
     * @param wrapper 查询条件
     * @return 用户列表
     */
    @Override
    public List<User> selectList(Wrapper<User> wrapper) {
        return userMapper.selectList(wrapper);
    }

    /**
     * @param email
     * @param newPwd
     * @return 找回结果
     */
    @Override
    public Result findPassword(String email, String newPwd) {
        // 查找用户
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("email", email));

        // 如果用户不存在，返回失败
        if (user == null) {
            return Result.fail(404, "用户不存在");
        }

        // 设置新密码并加密
        user.setPassword(encryptPassword(newPwd));

        // 更新密码
        userMapper.updateById(user);

        // 删除缓存中的验证码
        redisService.delMailCode(email);

        // 返回成功
        return Result.success("修改成功");
    }

    /**
     * 更新符合条件的用户数据
     *
     * @param user    更新的数据
     * @param wrapper 更新条件
     * @return 更新的记录数
     */
    @Override
    public int up(User user, Wrapper wrapper) {
        return userMapper.update(user, wrapper);
    }
}
